﻿package extremefx.tools {
	/**
	 * @author Marcelo Volmaro
	 */
	public class StringUtils {
		private static const _whiteChars:Vector.<String> = Vector.<String>([
			"\u0020", "\u000A","\u000C", "\u0009", "\u000B", "\u000D", 
			"\u0085", "\u00A0", "\u1680", "\u2000", "\u2001", "\u2002", 
			"\u2003", "\u2004", "\u2005", "\u2006", "\u2007", "\u2008", 
			"\u2009", "\u200A", "\u200B", "\u2028", "\u2029", "\u3000", 
			"\uFEFF"]);
		
		/**
		 * Copies the characters in PStr to a Unicode character array.
		 * @param pStr The string to be converted
		 * @param pStart The starting position of a substring.
		 * @param pLen The length of the substring.
		 */
		public static function toCharArray(pStr:String, pStart:uint = 0, pLen:uint = 0):Array{
			var a:Array = pStr.split("");
			if (pLen != 0) a = a.slice(pStart, pStart+pLen);
			return a;
		}
		
		/**
		 * Removes all occurrences of a set of specified characters from the beginning and end of a String reference.
		 * @param _pStr A String reference.
		 * @param pChars An array of Unicode characters to be removed or a null reference.
		 * @return The String that remains after all occurrences of the characters in trimChars are removed from the beginning and end of this instance. If trimChars is a null reference, white space characters are removed instead. 
		 */
		public static function trim(pStr:String, pChars:Vector.<String> = null):String{
			if (pChars == null || pChars.length == 0) {
				return pStr.replace(/^\s+|\s+$/g, "");
			}
			
			var rx:String = "["+(pChars.join("").replace(/([\^\]\\-])/g, "\\\$1"))+"]+";
			return pStr.replace(new RegExp("^"+rx+"|"+rx+"$", "g"), "");
		}
		
		/**
		 * Removes all occurrences of a set of characters specified in an array from the end of a String reference.
		 * @param _pStr A String reference.
		 * @param pChars An array of Unicode characters to be removed or a null reference.
		 * @return The String that remains after all occurrences of the characters in trimChars are removed from the end. If trimChars is a null reference, white space characters are removed instead. 
		 */
		public static function trimEnd(pStr:String, pChars:Vector.<String> = null):String{
			if (pChars == null || pChars.length == 0) {
				return pStr.replace(/\s+$/g, "");
			}
			
			return pStr.replace(new RegExp("["+(pChars.join("").replace(/([\^\]\\-])/g, "\\\$1"))+"]+$", "g"), "");
		}
		
		/**
		 * Removes all occurrences of a set of characters specified in an array from the beginning of a String reference.
		 * @param _pStr A String reference.
		 * @param pChars An array of Unicode characters to be removed or a null reference.
		 * @return The String that remains after all occurrences of characters in trimChars are removed from the beginning. If trimChars is a null reference, white space characters are removed instead. 
		 */
		public static function trimStart(pStr:String, pChars:Vector.<String> = null):String{
			if (pChars == null || pChars.length == 0) {
				return pStr.replace(/^\s+/g, "");
			}

			return pStr.replace(new RegExp("^["+(pChars.join("").replace(/([\^\]\\-])/g, "\\\$1"))+"]+", "g"), "");
		}
		
		/**
		 * Right-aligns and pads a string so that its rightmost character is a specified distance from the beginning of the string.
		 * @param pStr A String reference.
		 * @param pWidth The number of characters in the resulting string, equal to the number of original characters plus any additional padding characters. 
		 * @param pChar A Unicode padding character, or nothing to use a Space as the padding character
		 * @return A new String that is equivalent to this instance, but right-aligned and padded on the left with as many paddingChar characters as needed to create a length of totalWidth. Or, if totalWidth is less than the length of this instance, a new String that is identical to this instance. 
		 */
		public static function padLeft(pStr:String, pWidth:int, pChar:String = null):String {
			if (pChar == null) pChar = " ";
			pWidth -= pStr.length;
			if (0 < pWidth) while (pWidth--) pStr = pChar + pStr;
			return pStr; 
		}
		
		/**
		 * Left-aligns the characters in this string, padding on the right with spaces or a specified Unicode character, for a specified total length. 
		 * @param pStr A String reference.
		 * @param pWidth The number of characters in the resulting string, equal to the number of original characters plus any additional padding characters. 
		 * @param pChar A Unicode padding character, or nothing to use a Space as the padding character
		 * @return A new String that is equivalent to this instance, but left-aligned and padded on the right with as many paddingChar characters as needed to create a length of totalWidth. Or, if totalWidth is less than the length of this instance, a new String that is identical to this instance. 
		 */
		public static function padRight(pStr:String, pWidth:int, pChar:String = null):String {
			if (pChar == null) pChar = " ";
			pWidth -= pStr.length;
			if (0 < pWidth) while (pWidth--) pStr += pChar;
			return pStr; 
		}
		
		/**
		 * Returns a String array containing the substrings in a String that are delimited by elements of a specified Char array.
		 * Delimiter characters are not included in the elements of the return value array. Delimiters are detected using an ordinal comparison.
		 * If this instance does not contain any of the characters in separator, the return value array consists of a single element that contains this instance. If the separator parameter is a null reference or contains no characters, white space characters are assumed to be the delimiters.
		 * If two delimiters are adjacent, or a delimiter is found at the beginning or end of this instance, the corresponding array element contains Empty
		 * @param pStr A String reference.
		 * @param pSeps An array of Unicode characters that delimit the substrings in this instance, an empty array containing no delimiters, or a null reference.
		 * @return An array whose elements contain the substrings in this instance that are delimited by one or more characters in separator.
		 * 
		 */
		public static function split(pStr:String, pSeps:Vector.<String> = null):Vector.<String> {
			if (pSeps == null) pSeps = _whiteChars;
			var indexes:Array = [];
			var foundAt:int, foundSep:String, i:uint, sl:uint, entry:Object;
			
			i = 0;
			while(foundSep = pSeps[i++]){
				sl = foundSep.length;
				foundAt = -sl;
				
				while(-1 < (foundAt = pStr.indexOf(foundSep, foundAt+sl))){
					indexes.push({f:foundAt, l:sl});
				} 
			}
			
			indexes.sortOn("f", Array.NUMERIC);
			
			i = 0;
			var result:Vector.<String> = new Vector.<String>();
			var start:uint = 0;
			
			while (entry = indexes[i++]){
				if (start != entry.f) {
					result.push(pStr.substring(start, entry.f));
				}
				
				start = entry.f + entry.l;
			}
			
			if (start < pStr.length) {
				result.push(pStr.substring(start));
			}
			
			return result;
		}
		
		/**
		 * Determines whether the beginning of a String matches the specified string.
		 * @param _pStr A String reference.
		 * @param _prefix The String to compare.
		 * @return true if value matches the beginning of this string; otherwise, false.
		 */
		public static function startsWith (_pStr:String, _prefix:String):Boolean {
			return (_pStr.substr(0, _prefix.length) == _prefix);
		}
		
		/**
		 * Determines whether the end of a String matches the specified string.
		 * @param _pStr A String reference.
		 * @param _prefix The String to compare.
		 * @return true if value matches the end of this instance; otherwise, false. 
		 */
		public static function endsWith (_pStr:String, _prefix:String):Boolean {
			return (_pStr.substr(_pStr.length - _prefix.length) == _prefix);
		}
	}
}
